package com.zbkj.service.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zbkj.common.constants.Constants;
import com.zbkj.common.exception.AppException;
import com.zbkj.common.model.device.Device;
import com.zbkj.common.model.monitor.ZfbMonitorDeviceBind;
import com.zbkj.common.model.monitor.ZfbMonitorEquipment;
import com.zbkj.common.model.traceable.ZfbDeviceBatchesItems;
import com.zbkj.common.model.traceable.ZfbDeviceMatchLog;
import com.zbkj.common.model.user.User;
import com.zbkj.common.request.ZfbMonitorDeviceBindRequest;
import com.zbkj.common.request.ZfbMonitorDeviceUnbindRequest;
import com.zbkj.common.response.ZfbOrderMonitorDataResponse;
import com.zbkj.common.response.monitor.BfDeviceInfoResponse;
import com.zbkj.common.utils.RedisUtil;
import com.zbkj.service.dao.monitor.ZfbMonitorDeviceBindDao;
import com.zbkj.service.service.*;
import com.zbkj.service.service.device.DeviceService;
import com.zbkj.service.service.monitor.IZfbMonitorEquipmentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author dazongzi
* @description ZfbMonitorDeviceBindServiceImpl 接口实现
* @date 2025-06-09
*/
@Service
@Slf4j
public class ZfbMonitorDeviceBindServiceImpl extends ServiceImpl<ZfbMonitorDeviceBindDao, ZfbMonitorDeviceBind> implements ZfbMonitorDeviceBindService {

    @Resource
    private ZfbMonitorDeviceBindDao dao;
    @Autowired
    private UserService userService;
    @Autowired
    private MerchantService merchantService;
    @Autowired
    private ZfbDeviceMatchLogService zfbDeviceMatchLogService;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private ZfbDeviceBatchesItemsService deviceBatchesItemsService;
    @Autowired
    private IZfbMonitorEquipmentService zfbMonitorEquipmentService;
    @Resource
    private RedisUtil redisUtil;

    /**
     * 绑定蓝牙网关到监控上
     *
     * @param zfbMonitorDeviceBindRequest
     * @param merId
     * @return
     */
    @Override
    public boolean bindDeviceToMonitor(ZfbMonitorDeviceBindRequest zfbMonitorDeviceBindRequest, Integer merId) {
        // 检查设备是否已绑定
        Integer userId = userService.getUserIdException();
        Device device = deviceService.getDeviceByImei(zfbMonitorDeviceBindRequest.getSerialNum());
        if (ObjectUtil.isNull(device)) {
            throw new AppException("蓝牙网关设备不存在");
        }

        LambdaQueryWrapper<ZfbMonitorEquipment> lqw = Wrappers.lambdaQuery();
        lqw.eq(ZfbMonitorEquipment::getMerchantId, merId);
        lqw.eq(ZfbMonitorEquipment::getLicense, zfbMonitorDeviceBindRequest.getLicense());
        ZfbMonitorEquipment zfbMonitorEquipment = zfbMonitorEquipmentService.getOne(lqw);
        if (ObjectUtil.isNull(zfbMonitorEquipment)) {
            throw new AppException("未找到监控设备");
        }
        this.checkBind(device.getId(), zfbMonitorEquipment.getId());

        LambdaQueryWrapper<ZfbMonitorDeviceBind> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getMeid, zfbMonitorEquipment.getId());
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getDeviceId, device.getId());
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getIsDeleted, false);

        ZfbMonitorDeviceBind monitorDeviceBind = getOne(lambdaQueryWrapper);
        if (ObjectUtil.isNull(monitorDeviceBind)) {
            monitorDeviceBind = new ZfbMonitorDeviceBind();
            BeanUtils.copyProperties(zfbMonitorDeviceBindRequest, monitorDeviceBind);
            monitorDeviceBind.setDeviceId(device.getId());
            monitorDeviceBind.setMeid(zfbMonitorEquipment.getId());
        }
        monitorDeviceBind.setBindUid(userId);
        monitorDeviceBind.setBindTime(new Date());
        this.saveOrUpdate(monitorDeviceBind);
        return true;
    }

    @Override
    public void updateRefreshTime(String imei, String mac) {
        // 自动注册
        LambdaQueryWrapper<ZfbDeviceBatchesItems> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.select(ZfbDeviceBatchesItems::getId);
        checkWrapper.eq(ZfbDeviceBatchesItems::getDeviceMac, mac);
        checkWrapper.eq(ZfbDeviceBatchesItems::getIsDeleted, 0);
        checkWrapper.last("limit 1");
        ZfbDeviceBatchesItems recDevice = deviceBatchesItemsService.getOne(checkWrapper);
        if (recDevice == null) {
            recDevice = new ZfbDeviceBatchesItems();
            recDevice.setDeviceMac(mac);
            recDevice.setSn(mac);
            recDevice.setStatus(1);
            recDevice.setBatchesId(1);
            recDevice.setIsBad(false);
            deviceBatchesItemsService.save(recDevice);
        }

        ZfbDeviceMatchLog deviceMatchLog = zfbDeviceMatchLogService.getLatstByImeiMac(imei, mac);
        Device device = deviceService.getDeviceByImei(imei);
        if (ObjectUtil.isNull(device)) {
            log.warn("无法找到设备，IMEI: {}", imei);
            return;
        }
        ZfbMonitorDeviceBind deviceBind = getByImei(device.getId());
        if (ObjectUtil.isNull(deviceBind)) {
            log.warn("无法找到绑定关系，IMEI: {}/deviceId={}", imei, device.getId());
            return;
        }

        if (ObjectUtil.isNull(deviceMatchLog)) {
            deviceMatchLog = new ZfbDeviceMatchLog();
            // 通过mac找到设备明细，关联起来
            ZfbDeviceBatchesItems deviceBatchesItems = deviceBatchesItemsService.getIdByMac(mac);
            if (ObjectUtil.isNull(deviceBatchesItems)) {
                return;
            }
            deviceMatchLog.setItemsId(deviceBatchesItems.getId());
        }
        Date date = new Date();
        deviceMatchLog.setImei(imei);
        deviceMatchLog.setDeviceMac(mac);
        deviceMatchLog.setRefreshTime(date);
        deviceMatchLog.setBindId(deviceBind.getId());
        deviceMatchLog.setExpTime(DateUtil.offsetMinute(date, Constants.DEVICE_ON_LINE_TIME_MINUTE));
        zfbDeviceMatchLogService.saveOrUpdate(deviceMatchLog);
        // 更新设备表
        device.setIsOnline(true);
        device.setLastOnlineTime(date);
        deviceService.updateById(device);
        // 更新绑定表
        deviceBind.setLatestActiveTime(date);
        updateById(deviceBind);
    }

    @Override
    public List<ZfbOrderMonitorDataResponse> getOrderMonitorList(String orderNo) {
        return null;
    }

    @Override
    public List<ZfbMonitorDeviceBind> getMonitorList(String orderNo) {
        String now = DateUtil.now();
        return dao.findMonitorList(orderNo, now);
    }

    @Override
    public boolean unbind(ZfbMonitorDeviceUnbindRequest zfbMonitorDeviceBindRequest, Integer merId) {
        LambdaQueryWrapper<ZfbMonitorEquipment> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(ZfbMonitorEquipment::getMerchantId, merId);
        lambdaQueryWrapper.eq(ZfbMonitorEquipment::getLicense, zfbMonitorDeviceBindRequest.getLicense());
        ZfbMonitorEquipment zfbMonitorEquipment = zfbMonitorEquipmentService.getOne(lambdaQueryWrapper);
        if (ObjectUtil.isNull(zfbMonitorEquipment)) {
            throw new AppException("未找到监控设备");
        }
        LambdaQueryWrapper<ZfbMonitorDeviceBind> lqw = Wrappers.lambdaQuery();
        lqw.eq(ZfbMonitorDeviceBind::getMeid, zfbMonitorEquipment.getId());
        lqw.eq(ZfbMonitorDeviceBind::getIsDeleted, false);
        ZfbMonitorDeviceBind zfbMonitorDeviceBind = getOne(lqw);
        if (ObjectUtil.isNull(zfbMonitorDeviceBind)) {
            throw new AppException("未找到绑定关系，无法解绑");
        }
        ZfbMonitorDeviceBind ZfbMonitorDeviceBindUpdate = new ZfbMonitorDeviceBind();
        ZfbMonitorDeviceBindUpdate.setId(zfbMonitorDeviceBind.getId());
        ZfbMonitorDeviceBindUpdate.setIsDeleted(true);
        this.updateById(ZfbMonitorDeviceBindUpdate);
        return true;
    }

    @Override
    public void updateStatus(String imei, String outMac, String res) {
        Device device = deviceService.getDeviceByImei(imei);

        LambdaQueryWrapper<ZfbMonitorDeviceBind> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getDeviceId, device.getId());
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getIsDeleted, false);
        ZfbMonitorDeviceBind monitorDeviceBind = getOne(lambdaQueryWrapper);
        if (ObjectUtil.isNull(monitorDeviceBind)) {
            log.warn("设备不存在,imei={},outMac={}", imei, outMac);
            return;
        }

        String resKey = "monitor:" + imei + ":" + outMac + ":status:res";//格式：866240079984857:CE:04:40:06:00:10:status:res
        redisUtil.set(resKey, res, 2l, TimeUnit.MINUTES);

        // 当前亮灯的用户
        String license = zfbMonitorEquipmentService.getLicenseById(monitorDeviceBind.getMeid());
        if (StrUtil.isNotBlank(license)) {
            String key = "monitor:" + license + ":send";
            redisUtil.delete(key);

            String userKey = "monitor:" + license + ":view-user";
            redisUtil.delete(userKey);
        }

    }

    @Override
    public BfDeviceInfoResponse getBfDevice(String license, Integer merId) {
        LambdaQueryWrapper<ZfbMonitorEquipment> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(ZfbMonitorEquipment::getMerchantId, merId);
        lambdaQueryWrapper.eq(ZfbMonitorEquipment::getLicense, license);
        ZfbMonitorEquipment zfbMonitorEquipment = zfbMonitorEquipmentService.getOne(lambdaQueryWrapper);
        if (ObjectUtil.isNull(zfbMonitorEquipment)) {
            throw new AppException("未找到监控设备");
        }

        LambdaQueryWrapper<ZfbMonitorDeviceBind> lqw = Wrappers.lambdaQuery();
        lqw.eq(ZfbMonitorDeviceBind::getMeid, zfbMonitorEquipment.getId());
        lqw.eq(ZfbMonitorDeviceBind::getIsDeleted, false);
        ZfbMonitorDeviceBind one = getOne(lqw);
        BfDeviceInfoResponse bfDeviceInfoResponse = new BfDeviceInfoResponse();
        if (ObjectUtil.isNotNull(one)) {
            LambdaQueryWrapper<Device> lqwDevice = Wrappers.lambdaQuery();
            lqwDevice.eq(Device::getId, one.getDeviceId());
            lqwDevice.eq(Device::getIsDeleted, false);
            Device device = deviceService.getOne(lqwDevice);
            if (ObjectUtil.isNotNull(device)) {
                bfDeviceInfoResponse.setSerialNum(device.getImei());
            }
        }
        return bfDeviceInfoResponse;
    }

    @Override
    public List<ZfbMonitorDeviceBind> getListInLicense(List<String> licenseList, Integer merId) {
        LambdaQueryWrapper<ZfbMonitorEquipment> lqw = Wrappers.lambdaQuery();
        lqw.select(ZfbMonitorEquipment::getId, ZfbMonitorEquipment::getLicense);
        if (merId != null && merId > 0) {
            lqw.eq(ZfbMonitorEquipment::getMerchantId, merId);
        }
        lqw.in(ZfbMonitorEquipment::getLicense, licenseList);
        List<ZfbMonitorEquipment> list = zfbMonitorEquipmentService.list(lqw);
        if (CollUtil.isNotEmpty(list)) {
            List<Integer> meIdList = list.stream().map(ZfbMonitorEquipment::getId).distinct().collect(Collectors.toList());
            Map<Integer, String> map = list.stream()
                    .collect(Collectors.toMap(ZfbMonitorEquipment::getId, x -> x.getLicense()));

            LambdaQueryWrapper<ZfbMonitorDeviceBind> lqwBind = Wrappers.lambdaQuery();
            lqwBind.in(ZfbMonitorDeviceBind::getMeid, meIdList);
            lqwBind.eq(ZfbMonitorDeviceBind::getIsDeleted, false);
            lqwBind.orderByDesc(ZfbMonitorDeviceBind::getLatestActiveTime);
            List<ZfbMonitorDeviceBind> bindList = list(lqwBind);
            bindList.stream().forEach(x -> {x.setLicense(map.get(x.getMeid()));});
            return bindList;
        }
        return null;
    }


    private ZfbMonitorDeviceBind getByImei(Long deviceId) {
        LambdaQueryWrapper<ZfbMonitorDeviceBind> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getDeviceId, deviceId);
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getIsDeleted, false);
       return getOne(lambdaQueryWrapper);
    }

    private void checkBind(Long id, Integer zfbMonitorEquipmentId) {
        LambdaQueryWrapper<ZfbMonitorDeviceBind> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getMeid, zfbMonitorEquipmentId);
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getDeviceId, id);
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getIsDeleted, false);
        int num = dao.selectCount(lambdaQueryWrapper);
        if (num > 0) {
            throw new AppException("无需重复绑定当前监控设备");
        }
        // 检查监控是否被别的蓝牙设备绑定
        lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getMeid, zfbMonitorEquipmentId);
        lambdaQueryWrapper.ne(ZfbMonitorDeviceBind::getDeviceId, id);
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getIsDeleted, false);
        num = dao.selectCount(lambdaQueryWrapper);
        if (num > 0) {
            throw new AppException("监控设备已绑定到别的蓝牙设备上");
        }

        lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.ne(ZfbMonitorDeviceBind::getMeid, zfbMonitorEquipmentId);
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getDeviceId, id);
        lambdaQueryWrapper.eq(ZfbMonitorDeviceBind::getIsDeleted, false);
        num = dao.selectCount(lambdaQueryWrapper);
        if (num > 0) {
            throw new AppException("蓝牙设备已绑定到别的监控设备上");
        }
    }

}

